﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Warehouse.Web.AppCode;
using System.Web.Script.Serialization;

namespace Warehouse.Web.Sales
{
    public partial class BillView : BasePage
    {
        const int DetailCount = 10;
        public DataAccess.SalesBillType BillType;
        public bool IsAdd = true;

        protected DataAccess.SalesBill SalesBill = new Warehouse.DataAccess.SalesBill()
        {
            SalesDate = DateTime.Now.Date
        };
        protected Payment Pay = new Payment()
        {
            Amount = 0
        };

        protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
            {
                this.IsAdd = !Request.QueryString.AllKeys.Contains("ID");

                base.RegisterClientScriptContent("alldistributor", new JavaScriptSerializer().Serialize(DataAccess.Distributor.GetDistributors()));
                base.RegisterClientScriptContent("allproducts", new JavaScriptSerializer().Serialize(DataAccess.ProductSpecificationView.GetList()));

                this.ddlTransactor.DataSource = new List<DataAccess.User>(new DataAccess.User[] { new DataAccess.User(){
                    LoginName=string.Empty,
                    Name="请选择"
                }}).Concat(DataAccess.User.GetList());
                this.ddlTransactor.DataBind();

                this.ddlWareHouse.DataSource = DataAccess.Warehouse.GetWarehouses().ToArray();
                this.ddlWareHouse.DataBind();

                this.ddlAssetAmount.DataSource = new List<DataAccess.AssetAccount>() { DataAccess.AssetAccount.Empty }.Concat(DataAccess.AssetAccount.GetAssetAccounts());
                this.ddlAssetAmount.DataBind();

                if (!this.IsAdd)
                {
                    Guid billId = new Guid(Request.QueryString["ID"]);
                    this.SalesBill = DataAccess.SalesBill.GetOne(p => p.ID == billId);
                    this.BillType = this.SalesBill.BillType;
                    switch (this.BillType)
                    {
                        case Warehouse.DataAccess.SalesBillType.Sales:
                        case Warehouse.DataAccess.SalesBillType.Return:
                            {
                                var paymentdetails = DataAccess.ReceiptDetail.GetReceiptDetailsBySalesBillID(billId);
                                if (paymentdetails.Length > 0)
                                {
                                    this.Pay.AccountID = paymentdetails[0].AccountID;
                                    this.Pay.Amount = paymentdetails[0].Amount;
                                }
                            }
                            break;
                        case Warehouse.DataAccess.SalesBillType.Gift:
                            break;
                    }

                    this.rptDetails.DataSource = DataAccess.SalesDetail.GetList(p => p.BillID == billId);
                    this.rptDetails.DataBind();


                    for (int i = 0; i < this.ddlWareHouse.Items.Count; i++)
                    {
                        if (this.ddlWareHouse.Items[i].Value == this.SalesBill.HouseID.ToString())
                        {
                            this.ddlWareHouse.SelectedIndex = i;
                            break;
                        }
                    }

                    for (int i = 0; i < this.ddlAssetAmount.Items.Count; i++)
                    {
                        if (this.ddlAssetAmount.Items[i].Value == this.Pay.AccountID.ToString())
                        {
                            this.ddlAssetAmount.SelectedIndex = i;
                            break;
                        }
                    }

                    for (int i = 0; i < this.ddlTransactor.Items.Count; i++)
                    {
                        if (this.ddlTransactor.Items[i].Value == this.SalesBill.Transactor)
                        {
                            this.ddlTransactor.SelectedIndex = i;
                            break;
                        }
                    }
                }
                else
                {
                    this.BillType = (DataAccess.SalesBillType)int.Parse(Request.QueryString["type"]);

                    this.rptDetails.DataSource = Enumerable.Range(0, DetailCount).Select(p => new
                    {
                        ID = string.Empty,
                        Price = string.Empty,
                        Count = string.Empty,
                        Amount = string.Empty,
                        Comments = string.Empty,
                        ProductSpecificationID = 0
                    }).ToArray();
                    this.rptDetails.DataBind();
                }
                SetView();
            }
        }

        void SetView()
        {
            this.acAddSales.Visible = this.IsAdd && this.BillType == Warehouse.DataAccess.SalesBillType.Sales;
            this.acAddGift.Visible = this.IsAdd && this.BillType == Warehouse.DataAccess.SalesBillType.Gift;
            this.acAddReturn.Visible = this.IsAdd && this.BillType == Warehouse.DataAccess.SalesBillType.Return;

            this.acModifySales.Visible = !this.IsAdd && this.BillType == Warehouse.DataAccess.SalesBillType.Sales && this.SalesBill.BillStatus != Warehouse.DataAccess.BillStatus.Invalid;
            this.acModifyGift.Visible = !this.IsAdd && this.BillType == Warehouse.DataAccess.SalesBillType.Gift && this.SalesBill.BillStatus != Warehouse.DataAccess.BillStatus.Invalid;
            this.acModifyReturn.Visible = !this.IsAdd && this.BillType == Warehouse.DataAccess.SalesBillType.Return && this.SalesBill.BillStatus != Warehouse.DataAccess.BillStatus.Invalid;

            if (!this.IsAdd)
            {
                base.RegisterClientScriptContent("", "window.EditModel=true;");
            }
            if (this.BillType == Warehouse.DataAccess.SalesBillType.Gift)
            {
                this.placePayment.Visible = false;
                this.pnlWrapper.CssClass += " gift";
                base.RegisterClientScriptContent("", "window.Price=0;");
            }
            else
            {
                this.placePayment.Visible = true;
            }
        }

        protected override void ProcessAjaxRequest(HttpContext context, string action)
        {
            switch (action)
            {
                case "AddSales":
                    {
                        var bill = GetBill(context);
                        var details = GetDetails(context, true, bill.HouseID);
                        var payment = GetPayment(context);

                        bill.ID = Guid.NewGuid();
                        bill.BillType = Warehouse.DataAccess.SalesBillType.Sales;
                        bill.BillStatus = Warehouse.DataAccess.BillStatus.Default;
                        bill.CreateDate = DateTime.Now;
                        bill.Creator = context.User.Identity.Name;

                        foreach (var d in details)
                        {
                            d.BillID = bill.ID;
                        }

                        DataAccess.ReceiptBill paybill = null;
                        DataAccess.ReceiptDetail paydetail = null;
                        if (payment != null)
                        {
                            if (payment.Amount > details.Sum(p => p.Amount))
                            {
                                throw new ApplicationException("付款金额不能大于总金额");
                            }
                            paybill = new Warehouse.DataAccess.ReceiptBill()
                            {
                                ID = Guid.NewGuid(),
                                CreateDate = bill.CreateDate,
                                Creator = bill.Creator,
                                SalesBillID = bill.ID,
                                ReceiptDate = bill.SalesDate,
                                SerialNumber = bill.SerialNumber,
                                DistributorID = bill.DistributorID,
                                Transactor = bill.Transactor,
                                BillStatus = Warehouse.DataAccess.BillStatus.Default,
                                IsExpense = false
                            };
                            paydetail = new Warehouse.DataAccess.ReceiptDetail()
                            {
                                BillID = paybill.ID,
                                AccountID = payment.AccountID,
                                Amount = payment.Amount
                            };
                        }

                        using (System.Transactions.TransactionScope scope = new System.Transactions.TransactionScope())
                        {
                            using (DataAccess.WarehouseClassesDataContext datacontext = new Warehouse.DataAccess.WarehouseClassesDataContext())
                            {
                                bill.Save(datacontext);
                                foreach (var d in details)
                                {
                                    d.Save(datacontext);
                                    DataAccess.DistributorPrice p = new Warehouse.DataAccess.DistributorPrice()
                                    {
                                        DistributorID = bill.DistributorID,
                                        ProductSpecificationID = d.ProductSpecificationID,
                                        SalePrice = d.Price
                                    };
                                    p.Save(datacontext);
                                }
                                if (paybill != null)
                                {
                                    paybill.Save(datacontext);
                                    paydetail.Save(datacontext);
                                }
                            }
                            scope.Complete();
                        }
                        WebUtil.WriteJsonResult(context, null);
                    }
                    break;
                case "AddGift":
                    {
                        var bill = GetBill(context);
                        var details = GetDetails(context, true, bill.HouseID);

                        bill.ID = Guid.NewGuid();
                        bill.BillType = Warehouse.DataAccess.SalesBillType.Gift;
                        bill.BillStatus = Warehouse.DataAccess.BillStatus.Default;
                        bill.CreateDate = DateTime.Now;
                        bill.Creator = context.User.Identity.Name;

                        foreach (var d in details)
                        {
                            d.BillID = bill.ID;
                            d.Price = 0;
                            d.Amount = 0;
                        }

                        using (System.Transactions.TransactionScope scope = new System.Transactions.TransactionScope())
                        {
                            using (DataAccess.WarehouseClassesDataContext datacontext = new Warehouse.DataAccess.WarehouseClassesDataContext())
                            {
                                bill.Save(datacontext);
                                foreach (var d in details)
                                {
                                    d.Save(datacontext);
                                }
                            }
                            scope.Complete();
                        }
                        WebUtil.WriteJsonResult(context, null);
                    }
                    break;
                case "AddReturn":
                    {
                        var bill = GetBill(context);
                        var details = GetDetails(context, false, bill.HouseID);
                        var payment = GetPayment(context);

                        bill.ID = Guid.NewGuid();
                        bill.BillType = Warehouse.DataAccess.SalesBillType.Return;
                        bill.BillStatus = Warehouse.DataAccess.BillStatus.Default;
                        bill.CreateDate = DateTime.Now;
                        bill.Creator = context.User.Identity.Name;

                        var inventory = DataAccess.InventoryView.GetList(p => p.HouseID == bill.HouseID).ToDictionary(p => p.ProductSpecificationID);
                        foreach (var d in details)
                        {
                            d.BillID = bill.ID;
                            if (!inventory.ContainsKey(d.ProductSpecificationID) || inventory[d.ProductSpecificationID].Count < d.Count)
                            {
                                throw new ApplicationException("产品库存不足");
                            }
                        }

                        DataAccess.ReceiptBill receiptbill = null;
                        DataAccess.ReceiptDetail receiptdetail = null;
                        if (payment != null)
                        {
                            if (payment.Amount > details.Sum(p => p.Amount))
                            {
                                throw new ApplicationException("收款金额不能大于总金额");
                            }
                            receiptbill = new Warehouse.DataAccess.ReceiptBill()
                            {
                                ID = Guid.NewGuid(),
                                CreateDate = bill.CreateDate,
                                Creator = bill.Creator,
                                SalesBillID = bill.ID,
                                ReceiptDate = bill.SalesDate,
                                SerialNumber = bill.SerialNumber,
                                DistributorID = bill.DistributorID,
                                Transactor = bill.Transactor,
                                BillStatus = Warehouse.DataAccess.BillStatus.Default,
                                IsExpense = true
                            };
                            receiptdetail = new Warehouse.DataAccess.ReceiptDetail()
                            {
                                BillID = receiptbill.ID,
                                AccountID = payment.AccountID,
                                Amount = payment.Amount
                            };
                        }

                        using (System.Transactions.TransactionScope scope = new System.Transactions.TransactionScope())
                        {
                            using (DataAccess.WarehouseClassesDataContext datacontext = new Warehouse.DataAccess.WarehouseClassesDataContext())
                            {
                                bill.Save(datacontext);
                                foreach (var d in details)
                                {
                                    d.Save(datacontext);
                                }
                                if (receiptbill != null)
                                {
                                    receiptbill.Save(datacontext);
                                    receiptdetail.Save(datacontext);
                                }
                            }
                            scope.Complete();
                        }
                        WebUtil.WriteJsonResult(context, null);
                    }
                    break;
                case "SaveSales":
                case "SaveGift":
                case "SaveReturn":
                    {
                        JavaScriptSerializer ser = new JavaScriptSerializer();
                        DataAccess.SalesBill bill = ser.Deserialize<DataAccess.SalesBill>(context.Request.Form["Bill"]);
                        DataAccess.SalesDetail[] details = ser.Deserialize<DataAccess.SalesDetail[]>(context.Request.Form["Details"]);

                        var oldBill = DataAccess.SalesBill.GetOne(p => p.ID == bill.ID);
                        oldBill.Summary = bill.Summary;
                        oldBill.Comments = bill.Comments;
                        oldBill.Save();
                        foreach (var d in details)
                        {
                            var oldDetail = DataAccess.SalesDetail.GetOne(p => p.ID == d.ID);
                            oldDetail.Comments = d.Comments;
                            oldDetail.Save();
                        }
                        WebUtil.WriteJsonResult(context, null);
                    }
                    break;
                case "InvalidSales":
                case "InvalidGift":
                case "InvalidReturn":
                    {
                        Guid billId = new Guid(context.Request.Form["ID"]);
                        DataAccess.SalesBill bill = DataAccess.SalesBill.GetOne(p => p.ID == billId);

                        DataAccess.ReceiptBill paymentbill = DataAccess.ReceiptBill.GetOne(p => p.SalesBillID == bill.ID);

                        bill.BillStatus = Warehouse.DataAccess.BillStatus.Invalid;

                        if (paymentbill != null)
                        {
                            paymentbill.BillStatus = Warehouse.DataAccess.BillStatus.Invalid;
                            using (System.Transactions.TransactionScope scope = new System.Transactions.TransactionScope())
                            {
                                using (DataAccess.WarehouseClassesDataContext datacontext = new Warehouse.DataAccess.WarehouseClassesDataContext())
                                {
                                    bill.Save(datacontext);
                                    paymentbill.Save(datacontext);
                                }
                                scope.Complete();
                            }
                        }
                        else
                        {
                            bill.Save();
                        }
                        WebUtil.WriteJsonResult(context, null);
                    }
                    break;
                case "GetPrice":
                    {
                        int distributorId = int.Parse(context.Request.QueryString["DistributorID"]);
                        WebUtil.WriteJsonResult(context, DataAccess.DistributorPrice.Search(distributorId));
                    }
                    break;
                case "GetInventory":
                    {
                        int houseID = int.Parse(context.Request.QueryString["HouseID"]);
                        WebUtil.WriteJsonResult(context, DataAccess.InventoryView.GetList(p => p.HouseID == houseID));
                    }
                    break;
                default:
                    base.ProcessAjaxRequest(context, action);
                    break;
            }
        }

        DataAccess.SalesBill GetBill(HttpContext context)
        {
            JavaScriptSerializer ser = new JavaScriptSerializer();
            DataAccess.SalesBill bill = ser.Deserialize<DataAccess.SalesBill>(context.Request.Form["Bill"]);
            bill.SerialNumber = bill.SerialNumber.Trim();
            if (string.IsNullOrEmpty(bill.SerialNumber))
            {
                throw new ApplicationException("单据号不能为空");
            }

            bill.Transactor = bill.Transactor.Trim();
            if (string.IsNullOrEmpty(bill.Transactor))
            {
                throw new ApplicationException("经手人不能为空");
            }
            return bill;
        }

        DataAccess.SalesDetail[] GetDetails(HttpContext context, bool checkInventory, int houseId)
        {
            JavaScriptSerializer ser = new JavaScriptSerializer();
            DataAccess.SalesDetail[] details = ser.Deserialize<DataAccess.SalesDetail[]>(context.Request.Form["Details"]);
            if (details.Length == 0)
            {
                throw new ApplicationException("产品列表不能为空");
            }
            List<DataAccess.InventoryView> inventories = null;
            if (checkInventory)
            {
                var house = DataAccess.Warehouse.GetOne(p => p.ID == houseId);
                if (house.HouseType == Warehouse.DataAccess.WarehouseType.Virtual)
                {
                    checkInventory = false;
                }
                else
                {
                    inventories = DataAccess.InventoryView.GetList(p => p.HouseID == houseId);
                }
            }
            foreach (var d in details)
            {
                if (d.Count < 1)
                {
                    throw new ApplicationException("数量必须大于0");
                }
                if (d.Price < 0)
                {
                    throw new ApplicationException("单价不能为负数");
                }
                //todo 检查库存
                if (checkInventory)
                {
                    var invent = inventories.SingleOrDefault(p => p.ProductSpecificationID == d.ProductSpecificationID);
                    if (invent == null || invent.Count < d.Count)
                    {
                        var spect = DataAccess.ProductSpecificationView.GetSingle(p => p.ID == d.ProductSpecificationID);
                        throw new ApplicationException(string.Format("{0} {1} {2} 库存不足，当前库存：{3}", spect.Name, spect.Grade, spect.Model, invent == null ? 0 : invent.Count));
                    }
                }
                d.Amount = d.Count * d.Price;
            }
            return details;
        }

        protected Payment GetPayment(HttpContext context)
        {
            JavaScriptSerializer ser = new JavaScriptSerializer();
            Payment payment = ser.Deserialize<Payment>(context.Request.Form["Payment"]);
            return payment;
        }

        protected class Payment
        {
            public int AccountID { get; set; }
            public double Amount { get; set; }
        }
    }
}
